<template>
  <teleport to="body"
    ><template v-if="isRender"
      ><transition :name="markTranName"
        ><div class="mark" v-show="showModal" :class="{ isMark: showMark }">
          <div class="mark-box flex">
            <span
              class="mark-close"
              :class="{ 'mark-close__noMark': !showMark }"
              v-if="showClose"
            >
              <svg-icon icon-class="close" @click="closeModal"></svg-icon>
            </span>
            <transition :name="contentTranName">
              <div ref="modalMain" v-show="showModal">
                <slot></slot></div
            ></transition>
          </div></div></transition></template
  ></teleport>
</template>

<script lang="ts" setup>
import { ref, watch, nextTick, computed, onBeforeUnmount, onMounted } from "vue";
import { getScrollWid } from "@/plugins/getScrollWid";

const props = withDefaults(
  defineProps<{
    // 是否该显示模态框
    modelValue: boolean;
    // 是否显示背景色
    showMark?: boolean;
    // 是否显示关闭按钮
    showClose?: boolean;
    // 是否可以点击mark将对话框关闭
    markClose?: boolean;
  }>(),
  {
    showMark: true,
    showClose: true,
    markClose: true,
  }
);
const emits = defineEmits<{
  (e: "update:modelValue", show: boolean): void;
}>();

/**
 * 是否关闭该模态框
 */
let showModal = ref<boolean>(false);
/**
 * 是否渲染此组件
 */
let isRender = ref<boolean>(false);

// 针对mark的transition组件的过渡名称
const markTranName = computed(() => (props.showMark ? "modal" : ""));
// 针对mark内的content的transition组件的过渡名称
const contentTranName = computed(() => (props.showMark ? "modal-content" : "modal"));

/**
 * 浏览器的可视高度改变则组件的根元素的高度也随之改变
 */
const handleToWid: () => void = (): void => {
  // 获取浏览器的可视高度
  const hei: number =
    globalThis.innerHeight ||
    document.body.clientHeight ||
    document.documentElement.clientHeight;
  // 获取浏览器的可视宽度
  const wid: number =
    globalThis.innerWidth ||
    document.body.clientWidth ||
    document.documentElement.clientWidth;
  if (
    (document.body.scrollHeight > hei || document.body.scrollWidth > wid) &&
    props.modelValue
  )
    document.body.style.cssText += `overflow: hidden;padding-right: ${getScrollWid()}px`;
  else if (
    (document.body.scrollHeight <= hei || document.body.scrollWidth <= wid) &&
    props.modelValue
  )
    document.body.style.cssText = "";
};

/**
 * 模态框的内容元素
 */
const modalMain = ref<HTMLElement>();
/**
 * 判断用户所点击的元素是否符合标准
 */
const judgeClick = (e: Event) => {
  const target: HTMLElement = e.target as HTMLElement;
  if (!modalMain.value?.contains(target)) emits("update:modelValue", false);
};

watch(
  (): boolean => props.modelValue,
  (show: boolean): void => {
    if (show) {
      // 给浏览器添加监听窗口大小变化的事件
      window.addEventListener("resize", handleToWid);
      isRender.value = true;
      nextTick(() => {
        showModal.value = true;
        handleToWid();
        setTimeout(() => {
          if (props.markClose) document.addEventListener("click", judgeClick);
        });
      });
    } else {
      window.removeEventListener("resize", handleToWid);
      document.body.style.cssText = "";
      showModal.value = false;
      setTimeout(() => (isRender.value = false), 300);
      if (props.markClose) document.removeEventListener("click", judgeClick);
    }
  }
);

onMounted(() => {
  if (props.modelValue) {
    isRender.value = true;
    window.addEventListener("resize", handleToWid);
    setTimeout(() => {
      showModal.value = true;
      handleToWid();
    }, 0);
  }
});

onBeforeUnmount(() => window.removeEventListener("resize", handleToWid));

// 关闭该模态框
const closeModal: () => void = (): void => emits("update:modelValue", false);
</script>

<style lang="scss" scoped>
.isMark {
  background-color: #000000d1;
}

.modal {
  @include fade(0.25s, ease);

  &-content {
    &-enter-active,
    &-leave-active {
      transition: transform 0.3s;
    }

    &-enter-from,
    &-leave-to {
      transform: translateY(-30px);
    }
  }
}
.mark {
  position: fixed;
  inset: 0;
  z-index: 2010;
  overflow: auto;

  &-box {
    position: relative;
    min-height: 550px;
    min-width: 920px;
    @include setWidHei(100%, 100%);
  }

  &-close {
    position: absolute;
    top: 3%;
    right: 3%;
    font-size: 30px;
    cursor: pointer;
    color: #fff;

    &__noMark {
      color: #000;
    }
  }
}
</style>
